﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using LabChecker.Models;
using System.IO;
using System.Xml.Linq;
using System.Xml;
using System.Xml.Schema;
using System.Reflection;

namespace LabChecker.Services
{
    public class TaskImportService
    {
        public Task Deserialize(Stream InputStream)
        {
            IList<string> errors = new List<string>();
            XDocument _taskDocument;
            if (!GetVerifiedXDocumentFromStream(InputStream, out _taskDocument, out errors))
            {
                throw new InvalidOperationException("xml is invalid!!!");
            }
            var deserializedTask = new Task();
            var taskElement = _taskDocument.Descendants("{http://checker.org/Task}task").Single();
            var descriptionElement = taskElement.Element("{http://checker.org/Task}description");
            deserializedTask.Description.Title = (string)descriptionElement.Element("{http://checker.org/Task}title");
            deserializedTask.Description.Problem = (string)descriptionElement.Element("{http://checker.org/Task}problem");
            deserializedTask.Description.Input = (string)descriptionElement.Element("{http://checker.org/Task}input");
            deserializedTask.Description.Output = (string)descriptionElement.Element("{http://checker.org/Task}output");
            var dataElement = taskElement.Element("{http://checker.org/Task}data");
            foreach (var testCaseElement in dataElement.Descendants("{http://checker.org/Task}testCase"))
            {
                var deserializedTestCase = new TestCase();
                deserializedTestCase.Input = (string)testCaseElement.Element("{http://checker.org/Task}input");
                deserializedTestCase.Answer = (string)testCaseElement.Element("{http://checker.org/Task}answer");
                var messageElement = testCaseElement.Element("{http://checker.org/Task}message");
                deserializedTestCase.ErrorMessage = messageElement != null ? (string)messageElement : null;
                deserializedTestCase.IsExample = (bool?)testCaseElement.Attribute("isExample") ?? false;
                deserializedTask.TestCases.Add(deserializedTestCase);
            }
            return deserializedTask;
        }

        private bool GetVerifiedXDocumentFromStream(Stream InputStream, out XDocument document, out IList<string> errors)
        {
            errors = new List<string>();
            try
            {
                InputStream.Position = 0;
                document = XDocument.Load(new StreamReader(InputStream));
            }
            catch (XmlException ex)
            {
                errors.Add(ex.Message);
                document = null;
                return false;
            }

            var taskXmlSchema = XmlSchema.Read(Assembly.GetExecutingAssembly().GetManifestResourceStream("LabChecker.Core.infrastructure.serialization.TaskSchema.xsd"), null);
            var schemaSet = new XmlSchemaSet();
            schemaSet.Add(taskXmlSchema);
            if (document.Root.Name.NamespaceName != taskXmlSchema.TargetNamespace)
            {
                errors.Add("Пространство имён должно быть " + taskXmlSchema.TargetNamespace);
                return false;
            }
            try
            {
                document.Validate(schemaSet, null);
            }
            catch (XmlSchemaValidationException ex)
            {
                errors.Add(String.Format("{0}{1}Строка:{2} Позиция:{3}",
                                                            ex.Message, Environment.NewLine, ex.LineNumber, ex.LinePosition));
                return false;
            }
            return true;
        }
    }
}